using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Device_Link_LTSMC
{
	public sealed class LTSMC_Axis
	{
		/// <summary>
		/// 连接号
		/// </summary>
		private ushort ConnectNo { get; set; }

		private bool _isAlmLogic = false;
		/// <summary>
		/// 是否是绝对值坐标的模式
		/// </summary>
		public bool IsAbsMode { get; set; } = true;
		/// <summary>
		/// 异常事件
		/// </summary>
		public AxisErroCallBack ErroCallBack = null;
		/// <summary>
		/// 运行时堆栈
		/// </summary>
		private StackTrace _trace = new StackTrace();
		/// <summary>
		/// 获取当前正在运行的方法名称
		/// </summary>
		public string CurrentMethodName => _trace.GetFrame(0).GetMethod().Name;
		/// <summary>
		/// 起始速度
		/// </summary>
		public double StartSpeed { get; set; } = 10.0;
		/// <summary>
		/// 运行速度
		/// </summary>

		public double RunSpeed { get; set; } = 50.0;
		/// <summary>
		/// 回零速度
		/// </summary>
		public double ZeroSpeed { get; set; } = 50;
		/// <summary>
		/// 回零加速时间
		/// </summary>
		public double ZeroAcc { get; set; } = 0.1;
		/// <summary>
		/// 回零减速时间
		/// </summary>
		public double ZeroDec { get; set; } = 0.1;
		/// <summary>
		/// 加速时间
		/// </summary>

		public double AccTime { get; set; } = 0.1;
		/// <summary>
		/// 减速时间
		/// </summary>

		public double DecTime { get; set; } = 0.1;

		/// <summary>
		/// S段 平滑时间
		/// </summary>
		public double STime { get; set; } = 0.0;
		/// <summary>
		/// 轴
		/// </summary>

		public Axis TheAxis { get; } = Axis.X;
		public ushort AxisU => (ushort)TheAxis;
		/// <summary>
		/// 是否连接
		/// </summary>
		public bool IsLink { get; internal set; } = false;

		/// <summary>
		/// 停止速度
		/// </summary>
		public double StopSpeed { get; set; } = 100.0;

		/// <summary>
		/// 归零模式
		/// </summary>
		public ZeroMode ZeroMode { get; set; } = ZeroMode.一次回零加反找;
		/// <summary>
		/// 
		/// </summary>
		public OffectMode OffectMode { get; set; } = OffectMode.None;
		internal ushort OffectModeU => (ushort)OffectMode;
		public double OffectDistance { get; set; } = 0.0;
		/// <summary>
		/// 回零方向
		/// </summary>
		public Direction ToZeroDir { get; set; }
		/// <summary>
		/// 是否告警
		/// </summary>
		public bool IsWaring
		{
			get
			{
				uint num = LTSMC.smc_axis_io_status(ConnectNo, AxisU);
				if ((num & 1) == 1)
				{
					return true;
				}
				return false;
			}
		}

		private LTSMC_Axis()
		{
		}

		private LTSMC_Axis(Axis axis, ushort _connectNo)
		{
			TheAxis = axis;
			this.ConnectNo = _connectNo;
		}

		internal static LTSMC_Axis Instance(Axis axis, ushort _connectNo)
		{
			return new LTSMC_Axis(axis, _connectNo);
		}
		/// <summary>
		/// 检测轴是否异常
		/// </summary>
		/// <exception cref="LSTMCException"></exception>
		public void CheckAxis()
		{
			if (!IsLink)
			{
				throw new LSTMCException("请先连接设备!");
			}
			if (GetAxisCurrentState())
			{
				throw new LSTMCException(TheAxis.ToString() + "正在执行上一次的任务，请先关闭或结束前一次的任务!");
			}
			if (IsWaring)
			{
				throw new LSTMCException("伺服告警!轴向是：" + TheAxis);
			}
		}
		/// <summary>
		/// 获取轴当前的运行速度
		/// </summary>
		/// <returns></returns>
		public double GetAxisCurrentSpeed()
		{
			CheckAxis();
			double []current_speed  = new double[1];
			LTSMC.smc_read_current_speed_unit(ConnectNo, (ushort)TheAxis, ref current_speed);
			return current_speed[0];
		}
		/// <summary>
		/// 获取轴当前的坐标
		/// </summary>
		/// <returns></returns>
		public double GetAxisCurrentPosition()
		{
			double pos = 0.0;
			LTSMC.smc_get_position_unit(ConnectNo, (ushort)TheAxis, ref pos);
			return pos;
		}
		/// <summary>
		/// 获取轴当前的状态 true : 正在运动 false : 空闲
		/// </summary>
		/// <returns></returns>
		public bool GetAxisCurrentState()
		{
			return LTSMC.smc_check_done(ConnectNo, (ushort)TheAxis) != 1;
		}

		private void SetAxisSTime()
		{
			CheckAxis();
			CallBack("SetAxisSTime", LTSMC.smc_set_s_profile(ConnectNo, (ushort)TheAxis, 0, STime));
		}

		private void SetPulseMode()
		{
			CheckAxis();
			CallBack("SetPulseMode", LTSMC.smc_set_pulse_outmode(ConnectNo, (ushort)TheAxis, 0));
		}

		private void SetAllSpeed()
		{
			CheckAxis();
			CallBack("SetAllSpeed", LTSMC.smc_set_profile_unit(ConnectNo, (ushort)TheAxis, StartSpeed, RunSpeed, AccTime, DecTime, StopSpeed), LTSMC.smc_set_dec_stop_time(ConnectNo, (ushort)TheAxis, DecTime));
		}

		private void SetRunDistance(double position)
		{
			CheckAxis();
			CallBack("SetRunDistance", LTSMC.smc_pmove_unit(ConnectNo, (ushort)TheAxis, position, (ushort)(IsAbsMode ? 1 : 0)));
		}
		/// <summary>
		/// 移动到指定坐标
		/// </summary>
		/// <param name="position"></param>
		public void Move(double position)
		{
			SetAxisSTime();
			SetPulseMode();
			SetAllSpeed();
			SetRunDistance(position);
		}
		/// <summary>
		/// 异步运行
		/// </summary>
		/// <param name="position"></param>
		/// <returns></returns>
		public async Task MoveAsync(double position)
        {
			this.Move(position);
            while (GetAxisCurrentState())
            {
				await Task.Delay(200);
            }
        }
		/// <summary>
		/// 启动回零
		/// </summary>
		public void SetStartFindZeroParameters()
		{
			short[] array = new short[6];
			CheckAxis();
			array[0] = LTSMC.smc_set_pulse_outmode(ConnectNo, AxisU, 0);
			array[1] = LTSMC.smc_set_home_pin_logic(ConnectNo, AxisU, 0, 0.0);
			array[2] = LTSMC.smc_set_home_profile_unit(ConnectNo, AxisU, StartSpeed, ZeroSpeed, ZeroAcc, ZeroDec);
			array[3] = LTSMC.smc_set_homemode(ConnectNo, AxisU, (ushort)ToZeroDir, 1.0, (ushort)ZeroMode, 0);
			array[4] = LTSMC.smc_set_home_position_unit(ConnectNo, AxisU, OffectModeU, OffectDistance);
			array[5] = LTSMC.smc_home_move(ConnectNo, AxisU);
			CallBack("SetStartFindZeroParameters", array);
		}

		/// <summary>
		/// 设置是否是高电平 告警
		/// </summary>
		/// <param name="isHei"></param>
		public void SetAlmLogicALM(bool isHei)
		{
			CheckAxis();
			_isAlmLogic = isHei;
			CallBack("SetAlmLogicALM", LTSMC.smc_set_alm_mode(ConnectNo, AxisU, 1, (ushort)(isHei ? 1 : 0), 0));
		}

		public void SetInpMode(bool isenabel)
		{
			short[] array = new short[6];
			CheckAxis();
			array[0] = LTSMC.smc_set_inp_mode(ConnectNo, AxisU, (ushort)(isenabel ? 1 : 0), 0);
			CallBack("SetInpMode", array);
		}
		/// <summary>
		/// 读取停止原因
		/// </summary>
		/// <returns></returns>
		public int GetStopReason()
		{
			short[] array = new short[6];
			CheckAxis();
			int StopReason = 0;
			array[0] = LTSMC.smc_get_stop_reason(ConnectNo, AxisU, ref StopReason);
			CallBack("SetInpMode", array);
			return StopReason;
		}
		/// <summary>
		/// 异步启动回零
		/// </summary>
		/// <returns></returns>
		public async Task<bool> SetStartFindZeroParametersAsync()
		{
			CheckAxis();
			SetStartFindZeroParameters();
            while (GetAxisCurrentState())
            {
				await Task.Delay(100);
            }
			return true;
		}
		/// <summary>
		/// 启动单轴任务规划  PVT 模式
		/// </summary>
		/// <param name="data"></param>
		/// <exception cref="LSTMCException"></exception>
		public void SetSingleAxisAnySpeedTask(SingleAxisAnySpeedTaskData data)
		{
			CheckAxis();
			short[] array = new short[2];
			if (!data.IsReady)
			{
				throw new LSTMCException("单轴任意速度规划参数数据错误，可能位置和时间还有速率的长度不一致！");
			}
			if (data.IsBack)
			{
				data.SetAutoBack();
			}
			if (data.Mode == SingleSpeedTaskMode.PTT)
			{
				array[0] = LTSMC.smc_ptt_table_unit(ConnectNo, AxisU, (uint)data.Count, data.TimeArray, data.PositionArray);
			}
			else if (data.Mode == SingleSpeedTaskMode.PTS)
			{
				array[0] = LTSMC.smc_pts_table_unit(ConnectNo, AxisU, (uint)data.Count, data.TimeArray, data.PositionArray, data.PrecentArray);
			}
			else if (data.Mode == SingleSpeedTaskMode.PVT)
			{
				array[0] = LTSMC.smc_pvt_table_unit(ConnectNo, AxisU, (uint)data.Count, data.TimeArray, data.PositionArray, data.VelArray);
			}
			//array[1] = LTSMC.smc_pvt_move(ConnectNo, 1, new ushort[1] { AxisU });
			CallBack("SetSingleAxisAnySpeedTask", array);
		}
		/// <summary>
		/// 单轴任务规划
		/// </summary>
		/// <param name="length"></param>
		/// <param name="timeArray"></param>
		/// <param name="postionArray"></param>
		/// <param name="velArray"></param>
		public void SetSingleAxisAnySpeedTask(int length, double[] timeArray, double[] postionArray, double[] velArray)
		{
			CheckAxis();
			CallBack(erroCodes: new short[2]
			{
				LTSMC.smc_pvt_table_unit(ConnectNo, AxisU, (uint)length, timeArray, postionArray, velArray),
				LTSMC.smc_pvt_move(ConnectNo, 1, new ushort[1] { AxisU })
			}, optionFunction: CurrentMethodName);
		}
		/// <summary>
		/// 匀速一直运行
		/// </summary>
		/// <param name="dir"></param>
		public void MoveAlong(Direction dir)
		{
			CheckAxis();
			Move(0);
			CallBack(CurrentMethodName, LTSMC.smc_vmove(ConnectNo, AxisU, (ushort)dir));
		}

		public void SetPulseEnable(bool onOrOff)
		{
			CheckAxis();
			CallBack(CurrentMethodName, LTSMC.smc_write_sevon_pin(ConnectNo, AxisU, (ushort)(onOrOff ? 1 : 0)));
		}

		public void SetClearAxisWaring()
		{
			CallBack(CurrentMethodName, LTSMC.smc_write_erc_pin(ConnectNo, AxisU, (ushort)((!_isAlmLogic) ? 1 : 0)));
		}

		public void SetEmergencyStopIOMap(PortSatte state, ushort intPort)
		{
			CheckAxis();
			LTSMC.smc_set_axis_io_map(ConnectNo, AxisU, 3, 6, intPort, 0.0);
			LTSMC.smc_set_emg_mode(ConnectNo, AxisU, 1, (ushort)state);
		}

		public void SetEMGStopEnable(bool enable)
		{
			CheckAxis();
			LTSMC.smc_set_emg_mode(ConnectNo, AxisU, (ushort)(enable ? 1 : 0), 0);
		}

		public PortSatte GetEmergencyStopPortSatte(ushort intPort)
		{
			ushort emg_logic = 0;
			ushort enable = 1;
			short num = LTSMC.smc_get_emg_mode(ConnectNo, AxisU, ref enable, ref emg_logic);
			return (emg_logic != 0) ? PortSatte.H : PortSatte.L;
		}

		/// <summary>
		/// 坐标清零
		/// </summary>
		public void PositionZeroClear()
		{
			CheckAxis();
			CallBack(CurrentMethodName, LTSMC.smc_set_position_unit(ConnectNo, (ushort)TheAxis, 0.0));
		}

		public void DecAndStop()
		{
			CheckAxis();
			CallBack(CurrentMethodName, LTSMC.smc_stop(ConnectNo, (ushort)TheAxis, 0));
		}
		/// <summary>
		/// 改变运行中的速度
		/// </summary>
		/// <param name="speed"></param>
		public void SetRunningChangeSpeed(int speed = -1)
		{
			CheckAxis();
			if (speed != -1)
			{
				RunSpeed = speed;
			}
			CallBack(CurrentMethodName, LTSMC.smc_change_speed_unit(ConnectNo, (ushort)TheAxis, RunSpeed, 0.0));
		}

		public void Stop()
		{
			CallBack(CurrentMethodName, LTSMC.smc_stop(ConnectNo, (ushort)TheAxis, 1));
		}
		/// <summary>
		/// 修改运行中的坐标
		/// </summary>
		/// <param name="dis"></param>
		public void SetRunningChangeRunTargetDistance(int dis)
		{
			CheckAxis();
			CallBack(CurrentMethodName, LTSMC.smc_reset_target_position_unit(ConnectNo, (ushort)TheAxis, dis));
		}

		public AxisIOStutas ReadAxisIOStutas()
		{
			uint num = LTSMC.smc_axis_io_status(ConnectNo, (ushort)TheAxis);
			AxisIOStutas axisIOStutas = AxisIOStutas.Defult;
			foreach (AxisIOStutas value in Enum.GetValues(typeof(AxisIOStutas)))
			{
				if (((uint)value & num) != 0)
				{
					axisIOStutas |= value;
				}
			}
			return axisIOStutas;
		}

		private void CallBack(string optionFunction, params short[] erroCodes)
		{
			ErroType erroType = ErroType.EMPTY;
			StringBuilder stringBuilder = new StringBuilder();
			foreach (short num in erroCodes)
			{
				if (num != 0)
				{
					ErroType enumTypeByType = num.GetEnumTypeByType<ErroType, short>();
					stringBuilder.Append("错误" + enumTypeByType.ToString() + " : " + Tools.GetErroTypeTip(enumTypeByType) + "\n");
					erroType |= enumTypeByType;
				}
			}
			if (stringBuilder.Length == 0)
			{
				return;
			}
			throw new LSTMCException(string.Format("错误信息:{0}, 错误编码:{1}, 错误函数:{2}, 错误轴向:{3}", stringBuilder.ToString(), ((Func<short[], string>)delegate(short[] codes)
			{
				string text = "";
				foreach (short num2 in codes)
				{
					text = text + num2 + " ";
				}
				return text;
			})(erroCodes), optionFunction, TheAxis));
		}
	}
}
